/**
 * 
 */
package com.testvideo.command.mplayer;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import peer.player2.JavaAccess;

import com.testvideo.command.ClipInfoChangeEvent;
import com.testvideo.command.ClipInfoChangeListener;
import com.testvideo.command.IVideoPlayer;
import com.testvideo.command.VideoClipInfo;
import com.testvideo.ui.FleetPlayer;
import com.testvideo.util.CloseUtil;

/**
 * @author Administrator
 *
 */
public class BasicVideoPlayer extends MPlayerCommand implements IVideoPlayer, ClipInfoChangeListener {
	protected VideoClipInfo clipInfo ;
	protected FleetPlayer fleet ;
	private String filePlaying ;
	private String subtitleFilePlaying ;
	
	private float volume = 40 ;
	private long positionNow = 0 ;
	private float speed = 1 ;
	
	public BasicVideoPlayer(FleetPlayer fp) {
		super(null, null);		
		this.fleet = fp ;
		this.clipInfo = new VideoClipInfo() ;
		this.clipInfo.addClipInfoChangeListener(this) ;
	}
	
	public boolean isVideoLoaded(){
		return process != null ;
	}
	
	/**按照当前的所有参数，重新启动播放。*/
	public void restartPlay(){
		if(isVideoLoaded()){
			volume = (int) clipInfo.getVolume() ;
			positionNow = clipInfo.getAsLong("ANS_time_pos") ;
			speed = clipInfo.getAsFloat("ANS_speed") ;
			
			this.stop() ;
			this.play() ;
			this.seekTo(positionNow) ;
		}
	}

	public void activeFullScreen(boolean activeIt) {
		this.executeCommandKeepPausing(COMMAND_SET_PROPERTY, "fullscreen", activeIt? "1" : "0") ;
	}

	public void changeSpeed(float percentage) {
		this.executeCommandKeepPausing(COMMAND_SET_PROPERTY, "speed", percentage + "") ;
	}

	public void getPlayPositionNow() {
		executeCommandKeepPausing(COMMAND_GET_PROPERTY, "time_pos");
	}

	public void getVoiceLevel() {
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "volume");
	}

	public void isFullScreen() {
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "fullscreen");
	}

	public void isMute() {
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "mute");
	}

	public boolean isPaused() {
		return this.isPaused ;
	}

	public void mute(boolean muteIt) {
		this.executeCommandKeepPausing("mute", muteIt ? "1" : "0");
	}

	public boolean pause() {
		throw new RuntimeException("unsupported operation. use play() instead") ;
	}

	public void play() {
		if(!isVideoLoaded()){ //如果没有，播放上次的文件。
			if(this.filePlaying != null){
				this.playVideo(this.filePlaying, this.subtitleFilePlaying) ;
			}
		}else{
			this.executeCommandIgnorePausingProblem("pause");
			this.isPaused = !this.isPaused ;
			
			//this command alreadys return wrong value, and cause puzzles. stop it.
//			this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "pause") ;
			
			//send a message to tell listeners that pause status has changed.
			clipInfo.notifyNewEvent("ANS_pause", this.isPaused ? "yes" : "no") ;
		}
	}

	public void seekTo(long position) {
		this.executeCommandKeepPausing("seek", position + "", "2");
	}

	public void setVoice(int voice) {
		this.executeCommandKeepPausing(COMMAND_SET_PROPERTY, "volume", voice + "") ;
	}

	public void stop() {
		quit() ;
	}
	
	public void updateClipInfo(ClipInfoChangeEvent evt) {
		if(evt.match("ID_EXIT")){ //mplayer已经退出，清理。
			if(this.process == null) return ;			
			CloseUtil.close(sdi) ;
			CloseUtil.close(sdo) ;
			
			process.destroy() ;
			process = null ;
			
			if(errorHandlerThread != null){
				//退出以前的监听线程
				errorHandlerThread.quit() ;
				errorHandlerThread = null ;
			}
			
			this.clipInfo.changeStream(null, null) ;
		}
	}

	public synchronized void quit(){
		if(this.process == null) return ;
		
		this.executeCommandIgnorePausingProblem("quit", "0");
		
		CloseUtil.close(sdi) ;
		CloseUtil.close(sdo) ;
		
		process.destroy() ;
		process = null ;
		
		if(errorHandlerThread != null){
			//退出以前的监听线程
			errorHandlerThread.quit() ;
			errorHandlerThread = null ;
		}
		
		this.clipInfo.changeStream(null, null) ;
	}
	
	public void playVideo(String fileUrl, String subtitleUrl){
		this.stop() ;
		
		if(fileUrl == null) return ;
		
		this.filePlaying = fileUrl ;
		this.subtitleFilePlaying = subtitleUrl ;
		
		setupMPlayerProcess() ;
		
		//now we load file from the cmd line
//		this.executeCommandKeepPausing("loadfile", fileUrl); 
		refreshVideoProps() ;
		//TODO: add something to handle the subtitle
	}

	public VideoClipInfo getVideoClipInfo() {
		return clipInfo;
	}
	
	//发送一系列的命令，重新刷新视频信息。
	protected void refreshVideoProps(){
		clipInfo.clearVideoProps() ;
		
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "length") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "time_pos") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "volume") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "balance") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "mute") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "audio_delay") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "audio_format") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "audio_codec") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "audio_bitrate") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "samplerate") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "channels") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "fullscreen") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "ontop") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "framedropping") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "border") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "gamma") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "brightness") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "contrast") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "saturation") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "hue") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "panscan") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "vsync") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "video_format") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "video_codec") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "video_bitrate") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "width") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "height") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "fps") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_file") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_delay") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_pos") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_alignment") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_visibility") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_forced_only") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "sub_scale") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "osdlevel") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "speed") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "loop") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "pause") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "filename") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "path") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "stream_pos") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "stream_start") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "stream_end") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "stream_length") ;
		this.executeCommandKeepPausing(COMMAND_GET_PROPERTY, "metadata") ;
		this.executeCommandKeepPausing("get_time_length") ;
		this.executeCommandKeepPausing("get_video_resolution") ;
	}
		
	protected void setupMPlayerProcess(){
		try{
			if(hwnd < 0){
				hwnd=JavaAccess.getHWND(fleet.getCanvas(), System.getProperty("sun.boot.library.path")+"\\jawt.dll");
				System.out.println("hwnd:" + hwnd);
			}
			
			String command = "D:/tmp/SMPlayer/mplayer/mplayer.exe" ;
//			String command = "D:/tmp/lightvod/application/mplayer/MPlayer.exe" ;
			
			process = new ProcessBuilder(command, 
					"-identify", 
					"-quiet",
					"-slave",
//					"-idle",
					"-double",
					"-wid",
					"" + hwnd, 
					"-ao", "win32", 
					"-colorkey", "0x010101",
					"-nokeepaspect", 
					"-osdlevel",String.valueOf(0),
//					"-nomouseinput", 
					"-subcp", 
					"GBK", 
					"-subpos", 
					"100", 
					"-volume", 
					"" + volume, 
					"-cache", 
					"2048", 
					"-nofs", 
					"-sub-fuzziness", 
					"1",
					"-vo",
					"gl",
					"-adapter",
					"1",
					this.filePlaying
			).start();
			
			//启动成功，视频默认进行播放。
			this.isPaused = false ;
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
		sdi = new InputStreamReader(process.getInputStream());
		sdo = new OutputStreamWriter(process.getOutputStream());
				
		this.clipInfo.changeStream(sdi, sdo) ;
		
		if(errorHandlerThread != null){
			//退出以前的监听线程
			errorHandlerThread.quit() ;
		}
		
		errorHandlerThread = new ErrorHandlerThread() ;
		errorHandlerThread.setDaemon(true) ;
		errorHandlerThread.start() ;
	}	

	private Process process ;
	private ErrorHandlerThread errorHandlerThread ;
	private long hwnd = -1 ;
	
	private class ErrorHandlerThread extends Thread{
		
		private boolean shouldRunning = true ;
		
		public void quit(){
			shouldRunning = false ;
		}
		
		public void run(){
			InputStreamReader error = new InputStreamReader(process.getErrorStream()) ;
			while(shouldRunning){
				char[] c = new char[1024] ;
				try {
					if(error.read(c) > 0 ){
						System.err.println("error:" + new String(c)) ;
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}	
	
}
